package top.lcm889.juc.线程安全问题.test;

import top.lcm889.juc.线程安全问题.model.Account;

/**
 * @author Coder-lcm
 * @date 2021/4/10
 */
public class GetMoneyThread extends Thread{
    // 模拟用户账户
    private Account account;
    // 当前线程希望取的金额
    private double getMoneyCount;

    public GetMoneyThread(String name, Account account, double getMoneyCount){
        super(name);
        this.account = account;
        this.getMoneyCount = getMoneyCount;
    }

    /**
     * 当多个线程修改同一个共享数据时，将涉及数据安全问题
     *
     */
    @Override
    public void run() {
        //方式1： 使用同步代码块来保证线程安全
        // 同步代码块。这里是为了锁住account
//       synchronized (account){
//           if (account.getBalance() >= getMoneyCount) {
//               // 模拟吐出钞票
//               System.out.println(getName() + " 取钱成功！" + getMoneyCount);
//               try {
//                   Thread.sleep(1);
//               }catch (Exception e){
//                   e.printStackTrace();
//               }
//               //修改余额
//               account.setBalance(account.getBalance() -getMoneyCount);
//               System.out.println("\t余额为：" + account.getBalance());
//           }else {
//               System.out.println(getName() + ": 余额不足，取款失败");
//           }
//       }
        // 方式2： 直接调用对象的同步方法，也可实现线程安全
//       account.getMoneyOut(getMoneyCount);

       // 方式3 ： 调用对象通过可重入锁保证线程安全的方法来操作
        account.getMoneyOutByLock(getMoneyCount);

    }

    public static void main(String[] args) {
        Account account = new Account("sh231", 1000d);
        // 如果没有进行同步处理，会出问题
        new GetMoneyThread("Thread-A", account,800).start();
        new GetMoneyThread("Thread-B", account,800).start();
    }
}
